home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / CmplxMenu.c < prev    next >
C/C++ Source or Header  |  2001-06-23  |  41KB  |  1,405 lines

  1. /* (from) $XConsortium: SimpleMenu.c,v 1.41 92/09/10 16:25:07 converse Exp $ */
  2.  
  3. /*
  4.  * Modifications Copyright 1995, 1999 by Paul Mattes.
  5.  *  Permission to use, copy, modify, and distribute this software and its
  6.  *  documentation for any purpose and without fee is hereby granted,
  7.  *  provided that the above copyright notice appear in all copies and that
  8.  *  both that copyright notice and this permission notice appear in
  9.  *  supporting documentation.
  10.  *
  11.  * Copyright 1989 Massachusetts Institute of Technology
  12.  *
  13.  * Permission to use, copy, modify, distribute, and sell this software and its
  14.  * documentation for any purpose is hereby granted without fee, provided that
  15.  * the above copyright notice appear in all copies and that both that
  16.  * copyright notice and this permission notice appear in supporting
  17.  * documentation, and that the name of M.I.T. not be used in advertising or
  18.  * publicity pertaining to distribution of the software without specific,
  19.  * written prior permission.  M.I.T. makes no representations about the
  20.  * suitability of this software for any purpose.  It is provided "as is"
  21.  * without express or implied warranty.
  22.  *
  23.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  25.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  26.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  27.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  28.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  29.  */
  30.  
  31. /*
  32.  * ComplexMenu.c - Source code file for ComplexMenu widget.
  33.  * (from) SimpleMenu.c - Source code file for SimpleMenu widget.
  34.  *
  35.  * Date:    April 3, 1989
  36.  *
  37.  * By:      Chris D. Peterson
  38.  *          MIT X Consortium 
  39.  *          kit@expo.lcs.mit.edu
  40.  */
  41.  
  42. #include "globals.h"
  43. #if defined(X3270_MENUS) /*[*/
  44.  
  45. #include <stdio.h>
  46. #include <X11/IntrinsicP.h>
  47. #include <X11/StringDefs.h>
  48.  
  49. #include <X11/Xaw/XawInit.h>
  50. #include "CmplxMenuP.h"
  51. #include "CmeBSB.h"
  52. #include <X11/Xaw/Cardinals.h>
  53. #include <X11/Xaw/MenuButton.h>
  54.  
  55. #include <X11/Xmu/Initer.h>
  56. #include <X11/Xmu/CharSet.h>
  57.  
  58. #include <x11/X.h>
  59. #include <x11/Intrinsic.h>
  60. #include <x11/Shell.h>
  61. #include <x11/ShellP.h>
  62.  
  63. #define streq(a, b)        ( strcmp((a), (b)) == 0 )
  64.  
  65. #define offset(field) XtOffsetOf(ComplexMenuRec, complex_menu.field)
  66.  
  67. static XtResource resources[] = { 
  68.  
  69. /*
  70.  * Label Resources.
  71.  */
  72.  
  73.   {XtNlabel,  XtCLabel, XtRString, sizeof(String),
  74.      offset(label_string), XtRString, NULL},
  75.   {XtNlabelClass,  XtCLabelClass, XtRPointer, sizeof(WidgetClass),
  76.      offset(label_class), XtRImmediate, (XtPointer) NULL},
  77.  
  78. /*
  79.  * Layout Resources.
  80.  */
  81.  
  82.   {XtNrowHeight,  XtCRowHeight, XtRDimension, sizeof(Dimension),
  83.      offset(row_height), XtRImmediate, (XtPointer) 0},
  84.   {XtNtopMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
  85.      offset(top_margin), XtRImmediate, (XtPointer) 0},
  86.   {XtNbottomMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
  87.      offset(bottom_margin), XtRImmediate, (XtPointer) 0},
  88.  
  89. /*
  90.  * Misc. Resources
  91.  */
  92.  
  93.   { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
  94.       XtOffsetOf(ComplexMenuRec, shell.allow_shell_resize),
  95.       XtRImmediate, (XtPointer) TRUE },
  96.   {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  97.       offset(cursor), XtRImmediate, (XtPointer) None},
  98.   {XtNmenuOnScreen,  XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
  99.       offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
  100.   {XtNpopupOnEntry,  XtCPopupOnEntry, XtRWidget, sizeof(Widget),
  101.       offset(popup_entry), XtRWidget, NULL},
  102.   {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
  103.       offset(backing_store), 
  104.       XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
  105.   {XtNcMparent, XtCCMparent, XtRWidget, sizeof(Widget),
  106.       offset(parent), XtRWidget, NULL},
  107.   {XtNcMdefer, XtCCMdefer, XtRWidget, sizeof(Widget),
  108.       offset(deferred_notify), XtRWidget, NULL},
  109. };  
  110. #undef offset
  111.  
  112. static char defaultTranslations[] =
  113.     "<EnterWindow>:     highlight()             \n\
  114.      <LeaveWindow>:     leftWindow()            \n\
  115.      <BtnMotion>:       highlight()             \n\
  116.      <BtnUp>:           saveUnhighlight() MenuPopdown()"; 
  117.  
  118. /*
  119.  * Semi Public function definitions. 
  120.  */
  121.  
  122. static void Redisplay(Widget, XEvent *, Region);
  123. static void Realize(Widget, XtValueMask *, XSetWindowAttributes *);
  124. static void ChangeManaged(Widget);
  125. static void Resize(Widget);
  126. static void Initialize(Widget, Widget, ArgList, Cardinal *);
  127. static void ClassInitialize(void);
  128. static void ClassPartInitialize(WidgetClass);
  129. static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
  130. static Boolean SetValuesHook(Widget, ArgList, Cardinal *);
  131. static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
  132.     XtWidgetGeometry *);
  133.  
  134. /*
  135.  * Action Routine Definitions
  136.  */
  137.  
  138. static void PositionMenuAction(Widget, XEvent *, String *, Cardinal *);
  139. static void SaveUnhighlight(Widget, XEvent *, String *, Cardinal *);
  140. static void LeftWindow(Widget, XEvent *, String *, Cardinal *);
  141. static void Highlight(Widget, XEvent *, String *, Cardinal *);
  142.  
  143. /* 
  144.  * Private Function Definitions.
  145.  */
  146.  
  147. static void Unhighlight(), Notify();
  148. static void MakeSetValuesRequest(Widget, Dimension, Dimension);
  149. static void Layout(Widget, Dimension *, Dimension *);
  150. static void CreateLabel(Widget);
  151. static void AddPositionAction(XtAppContext, caddr_t);
  152. static void ChangeCursorOnGrab(Widget, XtPointer junk, XtPointer);
  153. static void PositionMenu(Widget, XPoint *);
  154. static void ClearParent(Widget, XtPointer, XtPointer);
  155. static Dimension GetMenuWidth(Widget, Widget);
  156. static Dimension GetMenuHeight(Widget);
  157. static Widget FindMenu(Widget, String);
  158. static CmeObject GetEventEntry(Widget, XEvent *);
  159. static CmeObject GetRightEntry(Widget, XEvent *);
  160. static void MoveMenu(Widget, Position, Position);
  161.  
  162. static XtActionsRec actionsList[] =
  163. {
  164.   {"highlight",         Highlight},
  165.   {"saveUnhighlight",   SaveUnhighlight},
  166.   {"leftWindow",    LeftWindow},
  167. };
  168.  
  169. static CompositeClassExtensionRec extension_rec = {
  170.     /* next_extension */  NULL,
  171.     /* record_type */     NULLQUARK,
  172.     /* version */         XtCompositeExtensionVersion,
  173.     /* record_size */     sizeof(CompositeClassExtensionRec),
  174.     /* accepts_objects */ TRUE,
  175. };
  176.  
  177. #ifndef AMIGA
  178. #define def_superclass (&overrideShellClassRec)
  179. #else
  180. #define def_superclass (overrideShellWidgetClass)
  181. #endif
  182.     
  183. ComplexMenuClassRec complexMenuClassRec = {
  184.   {
  185.     /* superclass         */    (WidgetClass)0,
  186.     /* class_name         */    "ComplexMenu",
  187.     /* size               */    sizeof(ComplexMenuRec),
  188.     /* class_initialize   */    ClassInitialize,
  189.     /* class_part_initialize*/    ClassPartInitialize,
  190.     /* Class init'ed      */    FALSE,
  191.     /* initialize         */    Initialize,
  192.     /* initialize_hook    */    NULL,
  193.     /* realize            */    Realize,
  194.     /* actions            */    actionsList,
  195.     /* num_actions        */    XtNumber(actionsList),
  196.     /* resources          */    resources,
  197.     /* resource_count     */    XtNumber(resources),
  198.     /* xrm_class          */    NULLQUARK,
  199.     /* compress_motion    */    TRUE, 
  200.     /* compress_exposure  */    TRUE,
  201.     /* compress_enterleave*/     TRUE,
  202.     /* visible_interest   */    FALSE,
  203.     /* destroy            */    NULL,
  204.     /* resize             */    Resize,
  205.     /* expose             */    Redisplay,
  206.     /* set_values         */    SetValues,
  207.     /* set_values_hook    */    SetValuesHook,
  208.     /* set_values_almost  */    0,  
  209.     /* get_values_hook    */    NULL,            
  210.     /* accept_focus       */    NULL,
  211.     /* intrinsics version */    XtVersion,
  212.     /* callback offsets   */    NULL,
  213.     /* tm_table          */    defaultTranslations,
  214.     /* query_geometry      */    NULL,
  215.     /* display_accelerator*/    NULL,
  216.     /* extension      */    NULL
  217.   },{
  218.     /* geometry_manager   */    GeometryManager,
  219.     /* change_managed     */    ChangeManaged,
  220.     /* insert_child      */    0,
  221.     /* delete_child      */    0,
  222.     /* extension      */    NULL
  223.   },{
  224.     /* Shell extension      */    NULL
  225.   },{
  226.     /* Override extension */    NULL
  227.   },{
  228.     /* Complex Menu extension*/  NULL
  229.   }
  230. };
  231.  
  232. WidgetClass complexMenuWidgetClass = (WidgetClass)&complexMenuClassRec;
  233.  
  234. #ifdef AMIGA
  235. void AMIGA_INIT_CMPLXMENU(void)
  236.  {
  237.  complexMenuClassRec.superclass=def_superclass;
  238.  complexMenuClassRec.set_values_almost=XtInheritSetValuesAlmost;
  239.  complexMenuClassRec.insert_child=XtInheritInsertChild;
  240.  complexMenuClassRec.delete_child=XtInheritDeleteChild;
  241.  }
  242. #endif
  243.  
  244. /************************************************************
  245.  *
  246.  * Semi-Public Functions.
  247.  *
  248.  ************************************************************/
  249.  
  250. /*      Function Name: ClassInitialize
  251.  *      Description: Class Initialize routine, called only once.
  252.  *      Arguments: none.
  253.  *      Returns: none.
  254.  */
  255.  
  256. void relay_func(
  257.     XrmValue*        a/* args */,
  258.     Cardinal*        b/* num_args */,
  259.     XrmValuePtr        c/* fromVal */,
  260.     XrmValuePtr        d/* toVal */
  261. )
  262. {
  263. XmuCvtStringToBackingStore(a,b,c,d);
  264. }
  265.  
  266. static void
  267. ClassInitialize(void)
  268. {
  269.   XawInitializeWidgetSet();
  270.   XtAddConverter( XtRString, XtRBackingStore, relay_func,
  271.          NULL, 0 );
  272.   XmuAddInitializer( AddPositionAction, NULL);
  273. }
  274.  
  275. /*      Function Name: ClassInitialize
  276.  *      Description: Class Part Initialize routine, called for every
  277.  *                   subclass.  Makes sure that the subclasses pick up 
  278.  *                   the extension record.
  279.  *      Arguments: wc - the widget class of the subclass.
  280.  *      Returns: none.
  281.  */
  282.  
  283. static void
  284. ClassPartInitialize(WidgetClass wc)
  285. {
  286.     ComplexMenuWidgetClass cmwc = (ComplexMenuWidgetClass) wc;
  287.  
  288. /*
  289.  * Make sure that our subclass gets the extension rec too.
  290.  */
  291.  
  292.     extension_rec.next_extension = cmwc->composite_class.extension;
  293.     cmwc->composite_class.extension = (XtPointer) &extension_rec;
  294. }
  295.  
  296. /*      Function Name: Initialize
  297.  *      Description: Initializes the complex menu widget
  298.  *      Arguments: request - the widget requested by the argument list.
  299.  *                 new     - the new widget with both resource and non
  300.  *                           resource values.
  301.  *      Returns: none.
  302.  */
  303.  
  304. static void
  305. Initialize(Widget request unused, Widget new, ArgList args unused,
  306.     Cardinal *num_args unused)
  307. {
  308.   ComplexMenuWidget cmw = (ComplexMenuWidget) new;
  309.  
  310.   XmuCallInitializers(XtWidgetToApplicationContext(new));
  311.  
  312.   if (cmw->complex_menu.label_class == NULL) 
  313.       cmw->complex_menu.label_class = cmeBSBObjectClass;
  314.  
  315.   cmw->complex_menu.label = NULL;
  316.   cmw->complex_menu.entry_set = NULL;
  317.   cmw->complex_menu.prev_entry = NULL;
  318.   cmw->complex_menu.recursive_set_values = FALSE;
  319.  
  320.   if (cmw->complex_menu.label_string != NULL)
  321.       CreateLabel(new);
  322.  
  323.   cmw->complex_menu.menu_width = TRUE;
  324.  
  325.   if (cmw->core.width == 0) {
  326.       cmw->complex_menu.menu_width = FALSE;
  327.       cmw->core.width = GetMenuWidth(new, (Widget)NULL);
  328.   }
  329.  
  330.   cmw->complex_menu.menu_height = TRUE;
  331.  
  332.   if (cmw->core.height == 0) {
  333.       cmw->complex_menu.menu_height = FALSE;
  334.       cmw->core.height = GetMenuHeight(new);
  335.   }
  336.  
  337. /*
  338.  * Add a popup_callback routine for changing the cursor.
  339.  */
  340.   
  341.   XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, NULL);
  342.  
  343. /*
  344.  * Add a popdown_callback routine for clearing the parent field.
  345.  */
  346.   
  347.   XtAddCallback(new, XtNpopdownCallback, ClearParent, NULL);
  348. }
  349.  
  350. /*      Function Name: Redisplay
  351.  *      Description: Redisplays the contents of the widget.
  352.  *      Arguments: w - the complex menu widget.
  353.  *                 event - the X event that caused this redisplay.
  354.  *                 region - the region the needs to be repainted. 
  355.  *      Returns: none.
  356.  */
  357.  
  358. static void
  359. Redisplay(Widget w, XEvent *event unused, Region region)
  360. {
  361.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  362.     CmeObject * entry;
  363.     CmeObjectClass class;
  364.  
  365.     if (region == NULL)
  366.     XClearWindow(XtDisplay(w), XtWindow(w));
  367.  
  368.     /*
  369.      * Check and Paint each of the entries - including the label.
  370.      */
  371.  
  372.     ForAllChildren(cmw, entry) {
  373.     if (!XtIsManaged ( (Widget) *entry)) continue;
  374.  
  375.     if (region != NULL) 
  376.         switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
  377.                  (int) (*entry)->rectangle.y,
  378.                  (unsigned int) (*entry)->rectangle.width,
  379.                  (unsigned int) (*entry)->rectangle.height)) {
  380.         case RectangleIn:
  381.         case RectanglePart:
  382.         break;
  383.         default:
  384.         continue;
  385.         }
  386.     class = (CmeObjectClass) (*entry)->object.widget_class;
  387.  
  388.     if (class->rect_class.expose != NULL)
  389.         (class->rect_class.expose)( (Widget) *entry, NULL, NULL);
  390.     }
  391. }
  392.  
  393. /*      Function Name: Realize
  394.  *      Description: Realizes the widget.
  395.  *      Arguments: w - the complex menu widget.
  396.  *                 mask - value mask for the window to create.
  397.  *                 attrs - attributes for the window to create.
  398.  *      Returns: none
  399.  */
  400.  
  401. static void
  402. Realize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
  403. {
  404.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  405.  
  406.     attrs->cursor = cmw->complex_menu.cursor;
  407.     *mask |= CWCursor;
  408.     if ((cmw->complex_menu.backing_store == Always) ||
  409.     (cmw->complex_menu.backing_store == NotUseful) ||
  410.     (cmw->complex_menu.backing_store == WhenMapped) ) {
  411.     *mask |= CWBackingStore;
  412.     attrs->backing_store = cmw->complex_menu.backing_store;
  413.     }
  414.     else
  415.     *mask &= ~CWBackingStore;
  416.  
  417.     (*def_superclass->core_class.realize) (w, mask, attrs);
  418. }
  419.  
  420. /*      Function Name: Resize
  421.  *      Description: Handle the menu being resized bigger.
  422.  *      Arguments: w - the complex menu widget.
  423.  *      Returns: none.
  424.  */
  425.  
  426. static void
  427. Resize(Widget w)
  428. {
  429.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  430.     CmeObject * entry;
  431.  
  432.     if ( !XtIsRealized(w) ) return;
  433.  
  434.     ForAllChildren(cmw, entry)     /* reset width of all entries. */
  435.     if (XtIsManaged( (Widget) *entry))
  436.         (*entry)->rectangle.width = cmw->core.width;
  437.     
  438.     Redisplay(w, (XEvent *) NULL, (Region) NULL);
  439. }
  440.  
  441. /*      Function Name: SetValues
  442.  *      Description: Relayout the menu when one of the resources is changed.
  443.  *      Arguments: current - current state of the widget.
  444.  *                 request - what was requested.
  445.  *                 new - what the widget will become.
  446.  *      Returns: none
  447.  */
  448.  
  449. static Boolean
  450. SetValues(Widget current, Widget request unused, Widget new,
  451.     ArgList args unused, Cardinal *num_args unused)
  452. {
  453.     ComplexMenuWidget cmw_old = (ComplexMenuWidget) current;
  454.     ComplexMenuWidget cmw_new = (ComplexMenuWidget) new;
  455.     Boolean ret_val = FALSE, layout = FALSE;
  456.     
  457.     if (!XtIsRealized(current)) return(FALSE);
  458.     
  459.     if (!cmw_new->complex_menu.recursive_set_values) {
  460.     if (cmw_new->core.width != cmw_old->core.width) {
  461.         cmw_new->complex_menu.menu_width = (cmw_new->core.width != 0);
  462.         layout = TRUE;
  463.     }
  464.     if (cmw_new->core.height != cmw_old->core.height) {
  465.         cmw_new->complex_menu.menu_height = (cmw_new->core.height != 0);
  466.         layout = TRUE;
  467.     }
  468.     }
  469.  
  470.     if (cmw_old->complex_menu.cursor != cmw_new->complex_menu.cursor)
  471.     XDefineCursor(XtDisplay(new),
  472.               XtWindow(new), cmw_new->complex_menu.cursor);
  473.     
  474.     if (cmw_old->complex_menu.label_string !=cmw_new->complex_menu.label_string) { 
  475.     if (cmw_new->complex_menu.label_string == NULL)         /* Destroy. */
  476.         XtDestroyWidget((Widget) cmw_old->complex_menu.label);
  477.     else if (cmw_old->complex_menu.label_string == NULL)    /* Create. */
  478.         CreateLabel(new);
  479.     else {                                                 /* Change. */
  480.         Arg arglist[1];
  481.         
  482.         XtSetArg(arglist[0], XtNlabel, cmw_new->complex_menu.label_string);
  483.         XtSetValues((Widget) cmw_new->complex_menu.label, arglist, ONE);
  484.     }
  485.     }
  486.     
  487.     if (cmw_old->complex_menu.label_class != cmw_new->complex_menu.label_class)
  488.     XtAppWarning(XtWidgetToApplicationContext(new),
  489.              "No Dynamic class change of the ComplexMenu Label.");
  490.     
  491.     if ((cmw_old->complex_menu.top_margin != cmw_new->complex_menu.top_margin) ||
  492.     (cmw_old->complex_menu.bottom_margin != 
  493.      cmw_new->complex_menu.bottom_margin) /* filler.................  */ ) {
  494.     layout = TRUE;
  495.     ret_val = TRUE;
  496.     }
  497.  
  498.     if (layout)
  499.     Layout(new, (Dimension *)NULL, (Dimension *)NULL);
  500.  
  501.     return(ret_val);
  502. }
  503.  
  504. /*      Function Name: SetValuesHook
  505.  *      Description: To handle a special case, this is passed the
  506.  *                   actual arguments.
  507.  *      Arguments: w - the menu widget.
  508.  *                 arglist - the argument list passed to XtSetValues.
  509.  *                 num_args - the number of args.
  510.  *      Returns: none
  511.  */
  512.  
  513. /* 
  514.  * If the user actually passed a width and height to the widget
  515.  * then this MUST be used, rather than our newly calculated width and
  516.  * height.
  517.  */
  518.  
  519. static Boolean
  520. SetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
  521. {
  522.     register Cardinal i;
  523.     Dimension width, height;
  524.     
  525.     width = w->core.width;
  526.     height = w->core.height;
  527.     
  528.     for ( i = 0 ; i < *num_args ; i++) {
  529.     if ( streq(arglist[i].name, XtNwidth) )
  530.         width = (Dimension) arglist[i].value;
  531.     if ( streq(arglist[i].name, XtNheight) )
  532.         height = (Dimension) arglist[i].value;
  533.     }
  534.  
  535.     if ((width != w->core.width) || (height != w->core.height))
  536.     MakeSetValuesRequest(w, width, height);
  537.     return(FALSE);
  538. }
  539.  
  540. /************************************************************
  541.  *
  542.  * Geometry Management routines.
  543.  *
  544.  ************************************************************/
  545.  
  546. /*    Function Name: GeometryManager
  547.  *    Description: This is the ComplexMenu Widget's Geometry Manager.
  548.  *    Arguments: w - the Menu Entry making the request.
  549.  *                 request - requested new geometry.
  550.  *                 reply - the allowed geometry.
  551.  *    Returns: XtGeometry{Yes, No, Almost}.
  552.  */
  553.  
  554. static XtGeometryResult
  555. GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
  556. {
  557.     ComplexMenuWidget cmw = (ComplexMenuWidget) XtParent(w);
  558.     CmeObject entry = (CmeObject) w;
  559.     XtGeometryMask mode = request->request_mode;
  560.     XtGeometryResult answer;
  561.     Dimension old_height, old_width;
  562.  
  563.     if ( !(mode & CWWidth) && !(mode & CWHeight) )
  564.     return(XtGeometryNo);
  565.  
  566.     reply->width = request->width;
  567.     reply->height = request->height;
  568.  
  569.     old_width = entry->rectangle.width;
  570.     old_height = entry->rectangle.height;
  571.  
  572.     Layout(w, &(reply->width), &(reply->height) );
  573.  
  574. /*
  575.  * Since we are an override shell and have no parent there is no one to
  576.  * ask to see if this geom change is okay, so I am just going to assume
  577.  * we can do whatever we want.  If you subclass be very careful with this
  578.  * assumption, it could bite you.
  579.  *
  580.  * Chris D. Peterson - Sept. 1989.
  581.  */
  582.  
  583.     if ( (reply->width == request->width) &&
  584.      (reply->height == request->height) ) {
  585.  
  586.     if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
  587.         entry->rectangle.width = old_width;
  588.         entry->rectangle.height = old_height;    
  589.     }
  590.     else {
  591.         Layout(( Widget) cmw, (Dimension *)NULL, (Dimension *)NULL);
  592.     }
  593.     answer = XtGeometryDone;
  594.     }
  595.     else {
  596.     entry->rectangle.width = old_width;
  597.     entry->rectangle.height = old_height;    
  598.  
  599.     if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
  600.           ((reply->height == request->height) && !(mode & CWWidth)) ||
  601.           ((reply->width == request->width) && 
  602.            (reply->height == request->height)) )
  603.         answer = XtGeometryNo;
  604.     else {
  605.         answer = XtGeometryAlmost;
  606.         reply->request_mode = 0;
  607.         if (reply->width != request->width)
  608.         reply->request_mode |= CWWidth;
  609.         if (reply->height != request->height)
  610.         reply->request_mode |= CWHeight;
  611.     }
  612.     }
  613.     return(answer);
  614. }
  615.  
  616. /*    Function Name: ChangeManaged
  617.  *    Description: called whenever a new child is managed.
  618.  *    Arguments: w - the complex menu widget.
  619.  *    Returns: none.
  620.  */
  621.  
  622. static void
  623. ChangeManaged(Widget w)
  624. {
  625.     Layout(w, (Dimension *)NULL, (Dimension *)NULL);
  626. }
  627.  
  628. /************************************************************
  629.  *
  630.  * Global Action Routines.
  631.  * 
  632.  * These actions routines will be added to the application's
  633.  * global action list. 
  634.  * 
  635.  ************************************************************/
  636.  
  637. /*      Function Name: PositionMenuAction
  638.  *      Description: Positions the complex menu widget.
  639.  *      Arguments: w - a widget (no the complex menu widget.)
  640.  *                 event - the event that caused this action.
  641.  *                 params, num_params - parameters passed to the routine.
  642.  *                                      we expect the name of the menu here.
  643.  *      Returns: none
  644.  */
  645.  
  646. static void
  647. PositionMenuAction(Widget w, XEvent *event, String *params,
  648.     Cardinal *num_params)
  649.   Widget menu;
  650.   XPoint loc;
  651.  
  652.   if (*num_params != 1) {
  653.     char error_buf[BUFSIZ];
  654.     (void) sprintf(error_buf, "%s %s",
  655.         "Xaw - ComplexMenuWidget: position menu action expects only one",
  656.         "parameter which is the name of the menu.");
  657.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  658.     return;
  659.   }
  660.  
  661.   if ( (menu = FindMenu(w, params[0])) == NULL) {
  662.     char error_buf[BUFSIZ];
  663.     (void) sprintf(error_buf, "%s '%s'",
  664.         "Xaw - ComplexMenuWidget: could not find menu named: ", params[0]);
  665.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  666.     return;
  667.   }
  668.   
  669.   switch (event->type) {
  670.   case ButtonPress:
  671.   case ButtonRelease:
  672.     loc.x = event->xbutton.x_root;
  673.     loc.y = event->xbutton.y_root;
  674.     PositionMenu(menu, &loc);
  675.     break;
  676.   case EnterNotify:
  677.   case LeaveNotify:
  678.     loc.x = event->xcrossing.x_root;
  679.     loc.y = event->xcrossing.y_root;
  680.     PositionMenu(menu, &loc);
  681.     break;
  682.   case MotionNotify:
  683.     loc.x = event->xmotion.x_root;
  684.     loc.y = event->xmotion.y_root;
  685.     PositionMenu(menu, &loc);
  686.     break;
  687.   default:
  688.     PositionMenu(menu, (XPoint *)NULL);
  689.     break;
  690.   }
  691. }  
  692.  
  693. /************************************************************
  694.  *
  695.  * Widget Action Routines.
  696.  * 
  697.  ************************************************************/
  698.  
  699. /*      Function Name: Unhighlight
  700.  *      Description: Unhighlights current entry.
  701.  *      Arguments: w - the complex menu widget.
  702.  *                 event - the event that caused this action.
  703.  *                 params, num_params - ** NOT USED **
  704.  *      Returns: none
  705.  */
  706.  
  707. static void
  708. Unhighlight(Widget w, XEvent *event unused, String *params unused,
  709.     Cardinal *num_params unused)
  710.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  711.     CmeObject entry = cmw->complex_menu.entry_set;
  712.     CmeObjectClass class;
  713.  
  714.     if ( entry == NULL) return;
  715.  
  716.     cmw->complex_menu.entry_set = NULL;
  717.     class = (CmeObjectClass) entry->object.widget_class;
  718.     (class->cme_class.unhighlight) ( (Widget) entry);
  719. }
  720.  
  721. static void
  722. SaveUnhighlight(Widget w, XEvent *event unused, String *params unused,
  723.     Cardinal *num_params unused)
  724.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  725.     CmeObject entry = cmw->complex_menu.entry_set;
  726.     CmeObjectClass class;
  727.  
  728.     if ( entry == NULL) return;
  729.  
  730.     cmw->complex_menu.prev_entry = entry;
  731.     cmw->complex_menu.entry_set = NULL;
  732.     class = (CmeObjectClass) entry->object.widget_class;
  733.     (class->cme_class.unhighlight) ( (Widget) entry);
  734. }
  735.  
  736. /*      Function Name: LeftWindow
  737.  *      Description: Mouse has left window, usually this means unhighlight
  738.  *      Arguments: w - the complex menu widget.
  739.  *                 event - the event that caused this action.
  740.  *                 params, num_params - ** NOT USED **
  741.  *      Returns: none
  742.  */
  743.  
  744. static void
  745. LeftWindow(Widget w, XEvent *event, String *params unused,
  746.     Cardinal *num_params unused)
  747.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  748.     CmeObject entry = cmw->complex_menu.entry_set;
  749.     CmeObjectClass class;
  750.     String mn;
  751.  
  752.     if ( entry == NULL) return;
  753.  
  754.     mn = NULL;
  755.     XtVaGetValues((Widget) entry, XtNmenuName, &mn, NULL);
  756.     if (mn != NULL && GetRightEntry(w, event) == entry)
  757.     return;
  758.  
  759.     cmw->complex_menu.prev_entry = NULL;
  760.     cmw->complex_menu.entry_set = NULL;
  761.     class = (CmeObjectClass) entry->object.widget_class;
  762.     (class->cme_class.unhighlight) ( (Widget) entry);
  763. }
  764.  
  765. /*      Function Name: Highlight
  766.  *      Description: Highlights current entry.
  767.  *      Arguments: w - the complex menu widget.
  768.  *                 event - the event that caused this action.
  769.  *                 params, num_params - ** NOT USED **
  770.  *      Returns: none
  771.  */
  772.  
  773. static void
  774. Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
  775. {
  776.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  777.     CmeObject entry;
  778.     CmeObjectClass class;
  779.     ShellWidget shell_widget = (ShellWidget)w;
  780.  
  781.     
  782. #if defined(CmeDebug)
  783.     printf("Highlight(%x)\n", w);
  784. #endif
  785.  
  786.     if (shell_widget->shell.popped_up != TRUE) {
  787. #if defined(CmeDebug)
  788.     printf("bogus\n");
  789. #endif
  790.     return;
  791.     }
  792.  
  793.     if ( !XtIsSensitive(w) ) return;
  794.     
  795.     entry = GetEventEntry(w, event);
  796.  
  797.     if (entry == cmw->complex_menu.entry_set) return;
  798.  
  799.     Unhighlight(w, event, params, num_params);  
  800.  
  801.     if (entry == NULL) return;
  802.  
  803.     if ( !XtIsSensitive( (Widget) entry)) {
  804.     cmw->complex_menu.entry_set = NULL;
  805.     return;
  806.     }
  807.  
  808.     cmw->complex_menu.entry_set = entry;
  809.     class = (CmeObjectClass) entry->object.widget_class;
  810.  
  811.     (class->cme_class.highlight) ( (Widget) entry);
  812. }
  813.  
  814. /*      Function Name: Notify
  815.  *      Description: Notify user of current entry.
  816.  *      Arguments: w - the complex menu widget.
  817.  *                 event - the event that caused this action.
  818.  *                 params, num_params - ** NOT USED **
  819.  *      Returns: none
  820.  */
  821.  
  822. static void
  823. Notify(Widget w, XEvent *event unused, String *params unused,
  824.     Cardinal *num_params unused)
  825. {
  826.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  827.     CmeObject entry = cmw->complex_menu.entry_set;
  828.     CmeObjectClass class;
  829.     
  830.     if (entry == NULL)
  831.     entry = cmw->complex_menu.prev_entry;
  832.     if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
  833.  
  834.     if (cmw->complex_menu.parent != NULL) {
  835. #if defined(CmeDebug)
  836.     printf("Notify(%x): deferring to %x to parent %x\n", w, entry,
  837.         cmw->complex_menu.parent);
  838. #endif
  839.     XtVaSetValues(cmw->complex_menu.parent, XtNcMdefer, (Widget)entry,
  840.         NULL);
  841.     return;
  842.     }
  843. #if defined(CmeDebug)
  844.     else
  845.     printf("Notify(%x): not deferring\n", w);
  846. #endif
  847.     if (cmw->complex_menu.deferred_notify != NULL) {
  848. #if defined(CmeDebug)
  849.     printf("Notify: using deferred %x\n", w,
  850.         cmw->complex_menu.deferred_notify);
  851. #endif
  852.     entry = (CmeObject)cmw->complex_menu.deferred_notify;
  853.     }
  854.     class = (CmeObjectClass) entry->object.widget_class;
  855.     (class->cme_class.notify)( (Widget) entry );
  856. }
  857.  
  858. /************************************************************
  859.  *
  860.  * Public Functions.
  861.  *
  862.  ************************************************************/
  863.  
  864. /*    Function Name: XawComplexMenuAddGlobalActions
  865.  *    Description: adds the global actions to the complex menu widget.
  866.  *    Arguments: app_con - the appcontext.
  867.  *    Returns: none.
  868.  */
  869.  
  870. void
  871. XawComplexMenuAddGlobalActions(XtAppContext app_con)
  872. {
  873.     XtInitializeWidgetClass(complexMenuWidgetClass);
  874.     XmuCallInitializers( app_con );
  875.  
  876.  
  877. /*    Function Name: XawComplexMenuGetActiveEntry
  878.  *    Description: Gets the currently active (set) entry.
  879.  *    Arguments: w - the cmw widget.
  880.  *    Returns: the currently set entry or NULL if none is set.
  881.  */
  882.  
  883. Widget
  884. XawComplexMenuGetActiveEntry(Widget w)
  885. {
  886.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  887.  
  888.     return( (Widget) cmw->complex_menu.entry_set);
  889.  
  890. /*    Function Name: XawComplexMenuClearActiveEntry
  891.  *    Description: Unsets the currently active (set) entry.
  892.  *    Arguments: w - the cmw widget.
  893.  *    Returns: none.
  894.  */
  895.  
  896. void
  897. XawComplexMenuClearActiveEntry(Widget w)
  898. {
  899.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  900.  
  901.     cmw->complex_menu.entry_set = NULL;
  902.     cmw->complex_menu.prev_entry = NULL;
  903.  
  904. /************************************************************
  905.  *
  906.  * Private Functions.
  907.  *
  908.  ************************************************************/
  909.  
  910. /*    Function Name: CreateLabel
  911.  *    Description: Creates a the menu label.
  912.  *    Arguments: w - the cmw widget.
  913.  *    Returns: none.
  914.  * 
  915.  * Creates the label object and makes sure it is the first child in
  916.  * in the list.
  917.  */
  918.  
  919. static void
  920. CreateLabel(Widget w)
  921. {
  922.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  923.     register Widget * child, * next_child;
  924.     register int i;
  925.     Arg args[2];
  926.  
  927.     if ( (cmw->complex_menu.label_string == NULL) ||
  928.      (cmw->complex_menu.label != NULL) ) {
  929.     char error_buf[BUFSIZ];
  930.  
  931.     (void) sprintf(error_buf, "Xaw Complex Menu Widget: %s or %s, %s",
  932.         "label string is NULL", "label already exists", 
  933.         "no label is being created.");
  934.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  935.     return;
  936.     }
  937.  
  938.     XtSetArg(args[0], XtNlabel, cmw->complex_menu.label_string);
  939.     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
  940.     cmw->complex_menu.label = (CmeObject) 
  941.                           XtCreateManagedWidget("menuLabel", 
  942.                         cmw->complex_menu.label_class, w,
  943.                         args, TWO);
  944.  
  945.     next_child = NULL;
  946.     for (child = cmw->composite.children + cmw->composite.num_children,
  947.      i = cmw->composite.num_children ; i > 0 ; i--, child--) {
  948.     if (next_child != NULL)
  949.         *next_child = *child;
  950.     next_child = child;
  951.     }
  952.     *child = (Widget) cmw->complex_menu.label;
  953. }
  954.  
  955. /*    Function Name: Layout
  956.  *    Description: lays the menu entries out all nice and neat.
  957.  *    Arguments: w - See below (+++)
  958.  *                 width_ret, height_ret - The returned width and 
  959.  *                                         height values.
  960.  *    Returns: none.
  961.  *
  962.  * if width == NULL || height == NULL then it assumes the you do not care
  963.  * about the return values, and just want a relayout.
  964.  *
  965.  * if this is not the case then it will set width_ret and height_ret
  966.  * to be width and height that the child would get if it were layed out
  967.  * at this time.
  968.  *
  969.  * +++ "w" can be the complex menu widget or any of its object children.
  970.  */
  971.  
  972. static void
  973. Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
  974. {
  975.     CmeObject current_entry, *entry;
  976.     ComplexMenuWidget cmw;
  977.     Dimension width, height;
  978.     Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
  979.     Boolean allow_change_size;
  980.     height = 0;
  981.  
  982.     if ( XtIsSubclass(w, complexMenuWidgetClass) ) {
  983.     cmw = (ComplexMenuWidget) w;
  984.     current_entry = NULL;
  985.     }
  986.     else {
  987.     cmw = (ComplexMenuWidget) XtParent(w);
  988.     current_entry = (CmeObject) w;
  989.     }
  990.  
  991.     allow_change_size = (!XtIsRealized((Widget)cmw) ||
  992.              (cmw->shell.allow_shell_resize));
  993.  
  994.     if ( cmw->complex_menu.menu_height )
  995.     height = cmw->core.height;
  996.     else
  997.     if (do_layout) {
  998.         height = cmw->complex_menu.top_margin;
  999.         ForAllChildren(cmw, entry) {
  1000.         if (!XtIsManaged( (Widget) *entry)) continue;
  1001.  
  1002.         if ( (cmw->complex_menu.row_height != 0) && 
  1003.             (*entry != cmw->complex_menu.label) ) 
  1004.             (*entry)->rectangle.height = cmw->complex_menu.row_height;
  1005.         
  1006.         (*entry)->rectangle.y = height;
  1007.         (*entry)->rectangle.x = 0;
  1008.         height += (*entry)->rectangle.height;
  1009.         }
  1010.         height += cmw->complex_menu.bottom_margin;
  1011.     }
  1012.     else {
  1013.         if ((cmw->complex_menu.row_height != 0) && 
  1014.         (current_entry != cmw->complex_menu.label) )
  1015.         height = cmw->complex_menu.row_height;
  1016.     }
  1017.     
  1018.     if (cmw->complex_menu.menu_width)
  1019.     width = cmw->core.width;
  1020.     else if ( allow_change_size )
  1021.     width = GetMenuWidth((Widget) cmw, (Widget) current_entry);
  1022.     else
  1023.     width = cmw->core.width;
  1024.  
  1025.     if (do_layout) {
  1026.     ForAllChildren(cmw, entry)
  1027.         if (XtIsManaged( (Widget) *entry)) 
  1028.         (*entry)->rectangle.width = width;
  1029.  
  1030.     if (allow_change_size)
  1031.         MakeSetValuesRequest((Widget) cmw, width, height);
  1032.     }
  1033.     else {
  1034.     *width_ret = width;
  1035.     if (height != 0)
  1036.         *height_ret = height;
  1037.     }
  1038. }
  1039.     
  1040. /*    Function Name: AddPositionAction
  1041.  *    Description: Adds the XawPositionComplexMenu action to the global
  1042.  *                   action list for this appcon.
  1043.  *    Arguments: app_con - the application context for this app.
  1044.  *                 data - NOT USED.
  1045.  *    Returns: none.
  1046.  */
  1047.  
  1048. static void
  1049. AddPositionAction(XtAppContext app_con, caddr_t data unused)
  1050. {
  1051.     static XtActionsRec pos_action[] = {
  1052.         { "XawPositionComplexMenu", PositionMenuAction },
  1053.     };
  1054.  
  1055.     XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
  1056. }
  1057.  
  1058. /*    Function Name: FindMenu
  1059.  *    Description: Find the menu give a name and reference widget.
  1060.  *    Arguments: widget - reference widget.
  1061.  *                 name   - the menu widget's name.
  1062.  *    Returns: the menu widget or NULL.
  1063.  */
  1064.  
  1065. static Widget 
  1066. FindMenu(Widget widget, String name)
  1067. {
  1068.     register Widget w, menu;
  1069.     
  1070.     for ( w = widget ; w != NULL ; w = XtParent(w) )
  1071.     if ( (menu = XtNameToWidget(w, name)) != NULL )
  1072.         return(menu);
  1073.     return(NULL);
  1074. }
  1075.  
  1076. /*    Function Name: PositionMenu
  1077.  *    Description: Places the menu
  1078.  *    Arguments: w - the complex menu widget.
  1079.  *                 location - a pointer the the position or NULL.
  1080.  *    Returns: none.
  1081.  */
  1082.  
  1083. static void
  1084. PositionMenu(Widget w, XPoint *location)
  1085. {
  1086.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1087.     CmeObject entry;
  1088.     XPoint t_point;
  1089.     
  1090.     if (location == NULL) {
  1091.     Window junk1, junk2;
  1092.     int root_x, root_y, junkX, junkY;
  1093.     unsigned int junkM;
  1094.     
  1095.     location = &t_point;
  1096.     if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2, 
  1097.               &root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
  1098.         char error_buf[BUFSIZ];
  1099.         (void) sprintf(error_buf, "%s %s", "Xaw - ComplexMenuWidget:",
  1100.             "Could not find location of mouse pointer");
  1101.         XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  1102.         return;
  1103.     }
  1104.     location->x = (short) root_x;
  1105.     location->y = (short) root_y;
  1106.     }
  1107.     
  1108.     /*
  1109.      * The width will not be correct unless it is realized.
  1110.      */
  1111.     
  1112.     XtRealizeWidget(w);
  1113.     
  1114.     location->x -= (Position) w->core.width/2;
  1115.     
  1116.     if (cmw->complex_menu.popup_entry == NULL)
  1117.     entry = cmw->complex_menu.label;
  1118.     else
  1119.     entry = cmw->complex_menu.popup_entry;
  1120.  
  1121.     if (entry != NULL)
  1122.     location->y -= entry->rectangle.y + entry->rectangle.height/2;
  1123.  
  1124.     MoveMenu(w, (Position) location->x, (Position) location->y);
  1125. }
  1126.  
  1127. /*    Function Name: MoveMenu
  1128.  *    Description: Actually moves the menu, may force it to
  1129.  *                   to be fully visable if menu_on_screen is TRUE.
  1130.  *    Arguments: w - the complex menu widget.
  1131.  *                 x, y - the current location of the widget.
  1132.  *    Returns: none 
  1133.  */
  1134.  
  1135. static void
  1136. MoveMenu(Widget w, Position x, Position y)
  1137. {
  1138.     Arg arglist[2];
  1139.     Cardinal num_args = 0;
  1140.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1141.     
  1142.     if (cmw->complex_menu.menu_on_screen) {
  1143.     int width = w->core.width + 2 * w->core.border_width;
  1144.     int height = w->core.height + 2 * w->core.border_width;
  1145.     
  1146.     if (x >= 0) {
  1147.         int scr_width = WidthOfScreen(XtScreen(w));
  1148.         if (x + width > scr_width)
  1149.         x = scr_width - width;
  1150.     }
  1151.     if (x < 0) 
  1152.         x = 0;
  1153.     
  1154.     if (y >= 0) {
  1155.         int scr_height = HeightOfScreen(XtScreen(w));
  1156.         if (y + height > scr_height)
  1157.         y = scr_height - height;
  1158.     }
  1159.     if (y < 0)
  1160.         y = 0;
  1161.     }
  1162.     
  1163.     XtSetArg(arglist[num_args], XtNx, x); num_args++;
  1164.     XtSetArg(arglist[num_args], XtNy, y); num_args++;
  1165.     XtSetValues(w, arglist, num_args);
  1166. }
  1167.  
  1168. /*    Function Name: ChangeCursorOnGrab
  1169.  *    Description: Changes the cursor on the active grab to the one
  1170.  *                   specified in out resource list.
  1171.  *    Arguments: w - the widget.
  1172.  *                 junk, garbage - ** NOT USED **.
  1173.  *    Returns: None.
  1174.  */
  1175.  
  1176. static void
  1177. ChangeCursorOnGrab(Widget w, XtPointer junk unused, XtPointer garbage unused)
  1178. {
  1179.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1180.     
  1181. #if defined(CmeDebug)
  1182.     printf("ChangeCursorOnGrab(%x): parent=%x\n", w, cmw->complex_menu.parent);
  1183. #endif
  1184.     cmw->complex_menu.deferred_notify = NULL;
  1185.     cmw->complex_menu.prev_entry = NULL;
  1186.     
  1187.     /*
  1188.      * The event mask here is what is currently in the MIT implementation.
  1189.      * There really needs to be a way to get the value of the mask out
  1190.      * of the toolkit (CDP 5/26/89).
  1191.      */
  1192.     
  1193.     XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
  1194.                  cmw->complex_menu.cursor, 
  1195.                  XtLastTimestampProcessed(XtDisplay(w)));
  1196. }
  1197.  
  1198. static void
  1199. ClearParent(Widget w, XtPointer junk unused, XtPointer garbage unused)
  1200. {
  1201.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1202.     
  1203. #if defined(CmeDebug)
  1204.     printf("ClearParent(%x): parent=%x\n", w, cmw->complex_menu.parent);
  1205. #endif
  1206.     Notify(w, (XEvent *)NULL, (String *)NULL, (Cardinal *)NULL);
  1207.     cmw->complex_menu.parent = NULL;
  1208. }
  1209.  
  1210. /*      Function Name: MakeSetValuesRequest
  1211.  *      Description: Makes a (possibly recursive) call to SetValues,
  1212.  *                   I take great pains to not go into an infinite loop.
  1213.  *      Arguments: w - the complex menu widget.
  1214.  *                 width, height - the size of the ask for.
  1215.  *      Returns: none
  1216.  */
  1217.  
  1218. static void
  1219. MakeSetValuesRequest(Widget w, Dimension width, Dimension height)
  1220. {
  1221.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1222.     Arg arglist[2];
  1223.     Cardinal num_args = (Cardinal) 0;
  1224.     
  1225.     if ( !cmw->complex_menu.recursive_set_values ) {
  1226.     if ( (cmw->core.width != width) || (cmw->core.height != height) ) {
  1227.         cmw->complex_menu.recursive_set_values = TRUE;
  1228.         XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
  1229.         XtSetArg(arglist[num_args], XtNheight, height); num_args++;
  1230.         XtSetValues(w, arglist, num_args);
  1231.     }
  1232.     else if (XtIsRealized( (Widget) cmw))
  1233.         Redisplay((Widget) cmw, (XEvent *) NULL, (Region) NULL);
  1234.     }
  1235.     cmw->complex_menu.recursive_set_values = FALSE;
  1236. }
  1237.  
  1238. /*      Function Name: GetMenuWidth
  1239.  *      Description: Sets the length of the widest entry in pixels.
  1240.  *      Arguments: w - the complex menu widget.
  1241.  *      Returns: width of menu.
  1242.  */
  1243.  
  1244. static Dimension
  1245. GetMenuWidth(Widget w, Widget w_ent)
  1246. {
  1247.     CmeObject cur_entry = (CmeObject) w_ent;
  1248.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1249.     Dimension width, widest = (Dimension) 0;
  1250.     CmeObject * entry;
  1251.     
  1252.     if ( cmw->complex_menu.menu_width ) 
  1253.     return(cmw->core.width);
  1254.  
  1255.     ForAllChildren(cmw, entry) {
  1256.     XtWidgetGeometry preferred;
  1257.  
  1258.     if (!XtIsManaged( (Widget) *entry)) continue;
  1259.     
  1260.     if (*entry != cur_entry) {
  1261.         XtQueryGeometry((Widget) *entry, NULL, &preferred);
  1262.         
  1263.         if (preferred.request_mode & CWWidth)
  1264.         width = preferred.width;
  1265.         else
  1266.         width = (*entry)->rectangle.width;
  1267.     }
  1268.     else
  1269.         width = (*entry)->rectangle.width;
  1270.     
  1271.     if ( width > widest )
  1272.         widest = width;
  1273.     }
  1274.     
  1275.     return(widest);
  1276. }
  1277.  
  1278. /*      Function Name: GetMenuHeight
  1279.  *      Description: Sets the length of the widest entry in pixels.
  1280.  *      Arguments: w - the complex menu widget.
  1281.  *      Returns: width of menu.
  1282.  */
  1283.  
  1284. static Dimension
  1285. GetMenuHeight(Widget w)
  1286. {
  1287.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1288.     CmeObject * entry;
  1289.     Dimension height;
  1290.     
  1291.     if (cmw->complex_menu.menu_height)
  1292.     return(cmw->core.height);
  1293.  
  1294.     height = cmw->complex_menu.top_margin + cmw->complex_menu.bottom_margin;
  1295.     
  1296.     if (cmw->complex_menu.row_height == 0) {
  1297.     ForAllChildren(cmw, entry) 
  1298.         if (XtIsManaged ((Widget) *entry)) 
  1299.         height += (*entry)->rectangle.height;
  1300.     } else 
  1301.     height += cmw->complex_menu.row_height * cmw->composite.num_children;
  1302.     
  1303.     return(height);
  1304. }
  1305.  
  1306. /*      Function Name: GetEventEntry
  1307.  *      Description: Gets an entry given an event that has X and Y coords.
  1308.  *      Arguments: w - the complex menu widget.
  1309.  *                 event - the event.
  1310.  *      Returns: the entry that this point is in.
  1311.  */
  1312.  
  1313. static CmeObject
  1314. GetEventEntry(Widget w, XEvent *event)
  1315. {
  1316.     Position x_loc = 0, y_loc = 0;
  1317.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1318.     CmeObject * entry;
  1319.     
  1320.     switch (event->type) {
  1321.     case MotionNotify:
  1322.     x_loc = event->xmotion.x;
  1323.     y_loc = event->xmotion.y;
  1324.     break;
  1325.     case EnterNotify:
  1326.     case LeaveNotify:
  1327.     x_loc = event->xcrossing.x;
  1328.     y_loc = event->xcrossing.y;
  1329.     break;
  1330.     case ButtonPress:
  1331.     case ButtonRelease:
  1332.     x_loc = event->xbutton.x;
  1333.     y_loc = event->xbutton.y;
  1334.     break;
  1335.     default:
  1336.     XtAppError(XtWidgetToApplicationContext(w),
  1337.            "Unknown event type in GetEventEntry().");
  1338.     break;
  1339.     }
  1340.     
  1341.     if ( (x_loc < 0) || (x_loc >= (int)cmw->core.width) || (y_loc < 0) ||
  1342.     (y_loc >= (int)cmw->core.height) )
  1343.     return(NULL);
  1344.     
  1345.     ForAllChildren(cmw, entry) {
  1346.     if (!XtIsManaged ((Widget) *entry)) continue;
  1347.  
  1348.     if ( ((*entry)->rectangle.y < y_loc) &&
  1349.             ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) ) {
  1350.         if ( *entry == cmw->complex_menu.label )
  1351.         return(NULL);    /* cannot select the label. */
  1352.         else
  1353.         return(*entry);
  1354.         }
  1355.     }
  1356.     
  1357.     return(NULL);
  1358. }
  1359.  
  1360. /*      Function Name: GetRightEntry
  1361.  *      Description: Gets an entry given a crossing event that has X and Y
  1362.  *                   coords, unless it exited to the right.
  1363.  *      Arguments: w - the complex menu widget.
  1364.  *                 event - the event.
  1365.  *      Returns: the entry that this point is in.
  1366.  */
  1367.  
  1368. static CmeObject
  1369. GetRightEntry(Widget w, XEvent *event)
  1370. {
  1371.     Position x_loc, y_loc;
  1372.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1373.     CmeObject * entry;
  1374.  
  1375.     x_loc = event->xcrossing.x;
  1376.     y_loc = event->xcrossing.y;
  1377.  
  1378.     if ( (x_loc < 0) || /*(x_loc < (int)cmw->core.width) ||*/ (y_loc < 0) ||
  1379.     (y_loc >= (int)cmw->core.height) )
  1380.     return(NULL);
  1381.  
  1382.     ForAllChildren(cmw, entry) {
  1383.     if (!XtIsManaged ((Widget) *entry)) continue;
  1384.  
  1385.     if ( ((*entry)->rectangle.y < y_loc) &&
  1386.             ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) ) {
  1387.         if ( *entry == cmw->complex_menu.label )
  1388.         return(NULL);    /* cannot select the label. */
  1389.         else
  1390.         return(*entry);
  1391.         }
  1392.     }
  1393.  
  1394.     return(NULL);
  1395. }
  1396.  
  1397. #endif /*]*/
  1398.